"use strict";
/**
 * @class chat.common 聊天相关通用方法
 * @description 提供坐席聊天相关通用方法
 */

define([], function () {
    //startsWith的polyfill
    if (!String.prototype.startsWith) {
        String.prototype.startsWith = function (searchString, position) {
            position = position || 0;
            return this.substr(position, searchString.length) === searchString;
        };
    }
    if (!String.prototype.replaceAll) {
        String.prototype.replaceAll = function (s1, s2) {
            return this.replace(new RegExp(s1, "gm"), s2);
        }
    }

    /**
     * 系统默认头像
     * @type {{WEIXIN: string, PC: string, PHONE: string}}
     */
    var ICONS = {
        CLIENT: {
            WECHAT: 'js/plugins/chat/images/wechat.png',
            PC: 'js/plugins/chat/images/pc.png',
            PHONE: 'js/plugins/chat/images/phone.png'
        },
        AGENT: {
            OTHER_AGENT: 'js/plugins/chat/images/agent.png',
            ELITE: 'js/plugins/chat/images/elite.gif',
            ROBOT: 'js/plugins/chat/images/robot.png'
        }
    };

    /**
     * 表情相关方法
     */
    var EMOTION = {
        QQ_EMOTION: {
            0: "微笑",
            1: "撇嘴",
            2: "色",
            3: "发呆",
            4: "得意",
            5: "流泪",
            6: "害羞",
            7: "闭嘴",
            8: "睡",
            9: "大哭",
            10: "尴尬",
            11: "发怒",
            12: "调皮",
            13: "呲牙",
            14: "惊讶",
            15: "难过",
            16: "酷",
            17: "冷汗",
            18: "抓狂",
            19: "吐",
            20: "偷笑",
            21: "愉快",
            22: "白眼",
            23: "傲慢",
            24: "饥饿",
            25: "困",
            26: "惊恐",
            27: "流汗",
            28: "憨笑",
            29: "悠闲",
            30: "奋斗",
            31: "咒骂",
            32: "疑问",
            33: "嘘",
            34: "晕",
            35: "疯了",
            36: "衰",
            37: "骷髅",
            38: "敲打",
            39: "再见",
            40: "擦汗",
            41: "抠鼻",
            42: "鼓掌",
            43: "糗大了",
            44: "坏笑",
            45: "左哼哼",
            46: "右哼哼",
            47: "哈欠",
            48: "鄙视",
            49: "委屈",
            50: "快哭了",
            51: "阴险",
            52: "亲亲",
            53: "吓",
            54: "可怜",
            55: "菜刀",
            56: "西瓜",
            57: "啤酒",
            58: "篮球",
            59: "乒乓",
            60: "咖啡",
            61: "饭",
            62: "猪头",
            63: "玫瑰",
            64: "凋谢",
            65: "嘴唇",
            66: "爱心",
            67: "心碎",
            68: "蛋糕",
            69: "闪电",
            70: "炸弹",
            71: "刀",
            72: "足球",
            73: "瓢虫",
            74: "便便",
            75: "月亮",
            76: "太阳",
            77: "礼物",
            78: "拥抱",
            79: "强",
            80: "弱",
            81: "握手",
            82: "胜利",
            83: "抱拳",
            84: "勾引",
            85: "拳头",
            86: "差劲",
            87: "爱你",
            88: "NO",
            89: "OK",
            90: "爱情",
            91: "飞吻",
            92: "跳跳",
            93: "发抖",
            94: "怄火",
            95: "转圈",
            96: "磕头",
            97: "回头",
            98: "跳绳",
            99: "投降",
            100: "激动",
            101: "乱舞",
            102: "献吻",
            103: "左太极",
            104: "右太极"
        },
        EMOJI_EMOTION: {
            "0": ":blush:",
            "1": ":fearful:",
            "2": ":heart_eyes:",
            "3": ":flushed:",
            "4": ":sunglasses:",
            "5": ":sob:",
            "6": ":relieved:",
            "7": ":dizzy_face:",
            "8": ":sleeping:",
            "9": ":cry:",
            "10": ":sweat_smile:",
            "11": ":rage:",
            "12": ":stuck_out_tongue_winking_eye:",
            "13": ":grinning:",
            "14": ":astonished:",
            "15": ":worried:",
            "16": ":triumph:",
            "17": ":disappointed:",
            "18": ":tired_face:",
            "19": ":persevere:",
            "20": ":smiling_imp:",
            "21": ":wink:",
            "22": ":hushed:",
            "23": ":confused:",
            "24": ":cold_sweat:",
            "25": ":yum:",
            "26": ":stuck_out_tongue_closed_eyes:",
            "27": ":sweat:",
            "28": ":smiley:",
            "29": ":joy:",
            "30": ":kissing_heart:",
            "31": ":unamused:",
            "32": ":smirk:",
            "33": ":no_mouth:",
            "34": ":scream:",
            "35": ":confounded:",
            "36": ":weary:",
            "37": ":pensive:",
            "38": ":expressionless:",
            "39": ":kissing_closed_eyes:",
            "40": ":sleepy:",
            "41": ":innocent:",
            "42": ":speak_no_evil:",
            "43": ":facepunch:",
            "44": ":-1:",
            "45": ":point_up:",
            "46": ":v:",
            "47": ":grimacing:",
            "48": ":mask:",
            "49": ":see_no_evil:",
            "50": ":ok_hand:",
            "51": ":clap:",
            "52": ":fist:",
            "53": ":muscle:",
            "54": ":laughing:",
            "55": ":relaxed:",
            "56": ":hear_no_evil:",
            "57": ":+1:",
            "58": ":pray:",
            "59": ":hand:",
            "60": ":sunny:",
            "61": ":coffee:",
            "62": ":snowman:",
            "63": ":books:",
            "64": ":gift:",
            "65": ":tada:",
            "66": ":icecream:",
            "67": ":cloud:",
            "68": ":snowflake:",
            "69": ":zap:",
            "70": ":moneybag:",
            "71": ":birthday:",
            "72": ":mortar_board:",
            "73": ":meat_on_bone:",
            "74": ":umbrella:",
            "75": ":partly_sunny:",
            "76": ":pencil2:",
            "77": ":hankey:",
            "78": ":christmas_tree:",
            "79": ":wine_glass:",
            "80": ":microphone:",
            "81": ":basketball:",
            "82": ":mahjong:",
            "83": ":bomb:",
            "84": ":loudspeaker:",
            "85": ":earth_asia:",
            "86": ":chocolate_bar:",
            "87": ":game_die:",
            "88": ":snowboarder:",
            "89": ":bulb:",
            "90": ":zzz:",
            "91": ":no_entry_sign:",
            "92": ":sunflower:",
            "93": ":beers:",
            "94": ":musical_note:",
            "95": ":house_with_garden:",
            "96": ":anger:",
            "97": ":telephone_receiver:",
            "98": ":shower:",
            "99": ":rice:",
            "100": ":family:",
            "101": ":angel:",
            "102": ":pill:",
            "103": ":gun:",
            "104": ":rose:",
            "105": ":dog:",
            "106": ":lipstick:",
            "107": ":couple:",
            "108": ":alien:",
            "109": ":kiss:",
            "110": ":crescent_moon:",
            "111": ":watermelon:",
            "112": ":pig:",
            "113": ":broken_heart:",
            "114": ":ghost:",
            "115": ":imp:",
            "116": ":ring:",
            "117": ":evergreen_tree:",
            "118": ":horse:",
            "119": ":crown:",
            "120": ":fire:",
            "121": ":star:",
            "122": ":soccer:",
            "123": ":clock7:",
            "124": ":alarm_clock:",
            "125": ":grin:",
            "126": ":rocket:",
            "127": ":hourglass_flowing_sand:",
            "128": ":smile:"
        },
        WECHAT_EMOTION: {
            0: "/::)", // 0
            1: "/::~", // 1
            2: "/::B", // 2
            3: "/::|", // 3
            4: "/:8-)", // 4
            5: "/::<", // 5
            6: "/::$", // 6
            7: "/::X", // 7
            8: "/::Z", // 8
            9: "/::'(", // 9
            10: "/::-|", // 10
            11: "/::@", // 11
            12: "/::P", // 12
            13: "/::D", // 13
            14: "/::O", // 14
            15: "/::(", // 15
            16: "/::+", // 16
            17: "/:–-b", // 17
            18: "/::Q", // 18
            19: "/::T", // 19
            20: "/:,@P", // 20
            21: "/:,@-D", // 21
            22: "/::d", // 22
            23: "/:,@o", // 23
            24: "/::g", // 24
            25: "/:|-)", // 25
            26: "/::!", // 26
            27: "/::L", // 27
            28: "/::>", // 28
            29: "/::,@", // 29
            30: "/:,@f", // 30
            31: "/::-S", // 31
            32: "/:?", // 32
            33: "/:,@x", // 33
            34: "/:,@@", // 34
            35: "/::8", // 35
            36: "/:,@!", // 36
            37: "/:!!!", // 37
            38: "/:xx", // 38
            39: "/:bye", // 39
            40: "/:wipe", // 40
            41: "/:dig", // 41
            42: "/:handclap", // 42
            43: "/:&-(", // 43
            44: "/:B-)", // 44
            45: "/:<@", // 45
            46: "/:@>", // 46
            47: "/::-O", // 47
            48: "/:>-|", // 48
            49: "/:P-(", // 49
            50: "/::'|", // 50
            51: "/:X-)", // 51
            52: "/::*", // 52
            53: "/:@x", // 53
            54: "/:8*", // 54
            55: "/:pd", // 55
            56: "/:<W>", // 56
            57: "/:beer", // 57
            58: "/:basketb", // 58
            59: "/:oo", // 59
            60: "/:coffee", // 60
            61: "/:eat", // 61
            62: "/:pig", // 62
            63: "/:rose", // 63
            64: "/:fade", // 64
            65: "/:showlove", // 65
            66: "/:heart", // 66
            67: "/:break", // 67
            68: "/:cake", // 68
            69: "/:li", // 69
            70: "/:bome", // 70
            71: "/:kn", // 71
            72: "/:footb", // 72
            73: "/:ladybug", // 73
            74: "/:shit", // 74
            75: "/:moon", // 75
            76: "/:sun", // 76
            77: "/:gift", // 77
            78: "/:hug", // 78
            79: "/:strong", // 79
            80: "/:weak", // 80
            81: "/:share", // 81
            82: "/:v", // 82
            83: "/:@)", // 83
            84: "/:jj", // 84
            85: "/:@@", // 85
            86: "/:bad", // 86
            87: "/:lvu", // 87
            88: "/:no", // 88
            89: "/:ok", // 89
            90: "/:love", // 90
            91: "/:<L>", // 91
            92: "/:jump", // 92
            93: "/:shake", // 93
            94: "/:<O>", // 94
            95: "/:circle", // 95
            96: "/:kotow", // 96
            97: "/:turn", // 97
            98: "/:skip", // 98
            99: "/:oY", // 99
            100: "/:#-0", // 100
            101: "/:hiphot", // 101
            102: "/:kiss", // 102
            103: "/:<&", // 103
            104: "/:&>" // 104
        },
        WECHAT_NEW_EMOTION: {
            17: '囧', // 这个非常奇怪，单独一个是[囧]，其他都是/:xxxx
            105: 'Hey',
            106: 'Facepalm',
            107: 'Smirk',
            108: 'Smart',
            109: 'Concerned',
            110: 'Yeah!',
            111: 'Chick',
            112: 'Packet',
            113: '發',
            114: '小狗'
        },
        
        /**
         * 转换微信表情成qq表情
         */ 
        parseWechatToQQ: function(msgText) {
        	// 微信表情比较特殊，要先把微信表情转换成qq表情字符
            for (var t in EMOTION.WECHAT_EMOTION) {
                var exp = EMOTION.WECHAT_EMOTION[t].replace(/\)/g, '\\)').replace(/\(/g, '\\(').replace(/\|/g, '\\|').replace(/\*/g, '\\*').replace(/\-/g, '\\-')
                    .replace(/\@/g, '\\@').replace(/\#/g, '\\#').replace(/\?/g, '\\?').replace(/\!/g, '\\!').replace(/\,/g, '\\,').replace(/\+/g, '\\+')
                    .replace(/\$/g, '\\$').replace(/\\'/g, '\\\'');
                var reg = new RegExp(exp, "gi"),
                    msgText = msgText.replace(reg, '[' + EMOTION.QQ_EMOTION[t] + ']');
            }
            return msgText;
        },
        /**
         * 过滤表情字符串为表情图片
         */
        filterEmojis: function (msgText) {
            // 装载QQ表情字符
            for (var t in EMOTION.QQ_EMOTION) {
                var reg = new RegExp("\\[" + EMOTION.QQ_EMOTION[t] + "\\]", "gi"),
                    msgText = msgText.replace(reg, '<img class="qqemoji qqemoji' + t + '" src="js/plugins/chat/images/spacer.gif" height="1" width="1" />');
            }
            // 装载标准emoji字符
            for (var t in EMOTION.EMOJI_EMOTION) {
            	var emoji = EMOTION.EMOJI_EMOTION[t];
            	emoji = emoji.replace(/\+/gi, '\\+');
                var reg = new RegExp('\\[' + emoji + '\\]', "gi"),
                    msgText = msgText.replace(reg, '<img class="standard-emoji standard-emoji' + t + '" src="js/plugins/chat/images/spacer.gif" height="1" width="1" />');
            }
            
            // 装载最新emoji
            var startChar = parseInt('001', 16), endChar = parseInt('538', 16);
            for (var i = 0; i < endChar - startChar; i++) {
                var emojiChar = (startChar + i).toString(16);
                while (emojiChar.length < 3) {
                    emojiChar = '0' + emojiChar;
                }
                var reg = new RegExp('\\ue' + emojiChar, 'gi');
                msgText = msgText.replace(reg, '<img class="standard-emoji-ue" src="js/plugins/chat/images/emoji/e' + emojiChar + '.png" />');
            }

            // 装载微信新表情 8个
            for (var t in EMOTION.WECHAT_NEW_EMOTION) {
                var reg = new RegExp('\\[' + EMOTION.WECHAT_NEW_EMOTION[t] + '\\]', "gi"),
                    msgText = msgText.replace(reg, '<img class="qqemoji qqemoji' + t + '" src="js/plugins/chat/images/spacer.gif" height="1" width="1" />');
            }
            return msgText;
        }
    };


    /**
     * 请求状态
     * @type {{waiting: number, accepted: number, refused: number, timeout: number, updateNumInQueue: number, blocked: number}}
     */
    var REQUEST_STATUS = {
        waiting: 0,
        accepted: 1,
        refused: 2,
        timeout: 3,
        updateNumInQueue: 8,
        blocked: 9
    };
    /**
     * 请求类型
     * @type {{clientRequest: number, agentInvite: number, agentTransfer: number}}
     */
    var CHAT_REQUEST_TYPE = {
        clientRequest: 1,
        agentInvite: 2,
        agentTransfer: 3,
        agentTransferToQueue: 4,
        wechatRequest: 11
    };

    /**
     * 坐席状态
     * @type {{ONLINE: number, OFFLINE: number}}
     */
    var USER_STATUS = {
        ONLINE: 1,
        OFFLINE: 2
    };

    /**
     * 客户类型
     */
    var CLIENT_TYPE = {
        NORMAL: 0,
        VISITOR: 1,
        WECHAT: 2,
        THIRD_PART: 3
    };

    /**
     * 通知消息类型
     */
    var NOTICE_TYPE = {
        NORMAL: 0,
        TRACK_CHANGE: 1,
        PUSH_RATING: 2,
        AFK_ELAPSED_NOTIFY: 3,
        AFK_ELAPSED_CLOSE_SESSION: 4,
        TYPING: 5,
        REVOKE_MESSAGE: 6,
        INVITE_NOTICE: 10,
        TRANSFER_NOTICE: 11,
        USER_LEFT_NOTICE: 12,
        CUSTOM: 99
    };

    /**
     * 消息声音
     * @param serverAddr
     * @constructor
     */
    var SoundManager = function (serverAddr) {
        this.sounds = {
            newRequestSound: new Audio(serverAddr + '/js/sound-manager/new_request_ding_dong.mp3'),
            newMessageSound: new Audio(serverAddr + '/js/sound-manager/new_msg.mp3')
        };
        this.play = function (soundName) {
            var audio = this.sounds[soundName];
            audio.play();
        }
    };

    var Tools = function (chatServerAddr) {
        this.chatServerAddr = chatServerAddr;
        this.chatServerHost = chatServerAddr.substring(0, chatServerAddr.lastIndexOf("/"));
        this.chatServerName = chatServerAddr.substring(chatServerAddr.lastIndexOf("/"), chatServerAddr.length);
    }

    Tools.prototype = {
        /**
         * 调用chat服务的ajax请求
         * @param url 请求地址
         * @param data 请求参数
         * @param chatServerAddr chat服务地址
         */
        callService: function (url, data) {
            url = this.chatServerAddr + "/" + url;
            return $.ajax({
                xhrFields: {
                    withCredentials: true
                },
                timeout: 10000,
                cache: false,
                method: "POST",
                url: url,
                data: data
            }).fail(function(xhr, textStatus, errorThrown) {
                $F.log('Chat - callService', 'Ajax fail: [STATUS:' + xhr.status + '] ' + textStatus + ' [url: ' + url + ']' + ' [data: ' + JSON.stringify(data) + ']');
            });
        },

        /**
         * 用来把img和a标签中的url地址里，不是绝对url地址的，自动拼接上chat的地址
         * 因为当前登录的ngs地址可能和chat服务地址不一致，如果是这样就会造成像是不出图片或者下载不到文件
         * 而原来的试用wanAddress的方式，其实是有问题的，因为发出去的消息，不是只发到客户的，可能是会议时候发给坐席的，所以不能直接简单的拼接上外网地址
         *
         * 同时过滤某些特殊html标签，比如script标签
         */
        parseDisplayContent: function (displayContent) {
        	if (Tools.isFormattedMsg(displayContent)) {
        		return displayContent;
        	} else {
        		var a = this;
        		//微信表情比较特殊，要先把微信表情转换成qq表情字符, 统一在这里处理，避免经过jquery的dom操作后，微信表情中的<>被认为是标签
        		displayContent = EMOTION.parseWechatToQQ(displayContent);
                var tempDiv = $('<div>').append(displayContent);
                tempDiv.find('img,a').filter(':not(.qqemoji,.standard-emoji, .standard-emoji-ue,.location)').each(function (i, v) {
                    var tag = $(v),
                        tagName = tag.prop('tagName'),
                        urlAttr = tagName === 'IMG' ? 'src' : 'href',
                        tagUrl = tag.attr(urlAttr);
                    if (tagUrl) {
                        if (tagUrl.startsWith('data:image/png;base64,')) {
                            //不处理dataURI的src
                        } else if (!tagUrl.toLowerCase().startsWith('http')) {
                            if (tagUrl.startsWith($E.url)) {
                                tag.attr(urlAttr, location.origin + tagUrl);
                            } else {
                                if (!tagUrl.startsWith('/'))
                                    tagUrl = '/' + tagUrl;
                                if (tagUrl.startsWith(a.chatServerName)) {
                                    tag.attr(urlAttr, a.chatServerHost + tagUrl);
                                } else {
                                    tag.attr(urlAttr, a.chatServerAddr + tagUrl);
                                }
                            }
                        } else if (tagUrl.toLowerCase().startsWith('http')) {
                            tagUrl = tagUrl.replace(a.chatServerHost, '');
                            tag.attr(urlAttr, tagUrl);
                        }
                    }
                });
                //过滤特殊html标签(script标签)
                tempDiv.find('script').remove();
                //自定义表情处理
                tempDiv.find('.custom-emoji').each(function (i, v) {
                    var tag = $(v);
                    tag.removeAttr('data-src');
                });
                return tempDiv.html();
        	}
        },

        /**
         * 发送消息之前，如果有自定义表情，需要对表情的url做一下处理
         * @param content
         * @returns
         */
        parseContent: function (content) {
        	if (Tools.isFormattedMsg(content)) {
        		return Tools.formatHtmlEntity(content);
        	} else {
        		var tempDiv = $('<div>').append(content);
                tempDiv.find('.custom-emoji').each(function (i, v) {
                    var tag = $(v);
                    tag.attr('src', tag.attr('data-src'));
                    tag.removeAttr('data-src');
                });
                content = tempDiv.html().replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&apos;/g, "'");
                return content;
        	}
        }
    }

    /**
     * 过滤字符中url，用a标签包装识别出来的url。只会包装dom元素的text内容，而不会去包装dom的属性中的url
     */
    Tools.wrapURL = function (str) {
        try {
            if ($(str).length > 0) {
                return str;
            }
        } catch (e) {
        }
        // 原来的正则必须包含http://或者https://     /(http:|https:)\/\/[A-Za-z0-9\._\?%&+\-=/#]*/gi
        var matchURLs = $('<div>').append(str).text().match(/(((https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www\..|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)(?::(\d+))?((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\+~%\/.\w-_\?=&;%@]*))?)/g);
        $.each(matchURLs, function (i, url) {
            //经过text()方法后，字符串中的&amp;会变成& 这里要判断一下，如果存在这种情况，就要再replace一次
            var parsedUrl = url.replace(/&/g, '&amp;');
            str = str.replace(parsedUrl, function (matchStr) {
                var url = matchStr;
                if (!matchStr.startsWith('http://') && !matchStr.startsWith('https://')) {
                    url = 'http://' + matchStr;
                }
                return '<a target="_blank" href="' + url + '">' + matchStr + '</a>';
            });
        });
        return str;
    };

    /**
     * 把元素添加到当前光标所在的位置
     */
    Tools.appendToEditDiv = function (element) {
        var o, n;
        if (window.getSelection) {
            o = window.getSelection(), n = o.getRangeAt(0), n.deleteContents();
            var r;
            if (n.createContextualFragment)
                r = n.createContextualFragment(element);
            else {
                var a = document.createElement("div");
                a.innerHTML = element, r = document.createDocumentFragment();
                for (var i, c; i = a.firstChild;)
                    c = r.appendChild(i)
            }
            var s = r.lastChild;
            n.insertNode(r), n.setStartAfter(s), o.removeAllRanges(), o.addRange(n);
        }
    };

    /**
     * 返回持续时长
     */
    Tools.getFormattedLasting = function (time) {
        var dt = new Date(time);
        var hours = Math.floor(time / 1000 / 60 / 60);
        var minutes = Math.floor((time - hours * 1000 * 60 * 60) / 1000 / 60);
        var seconds = Math.floor((time - hours * 1000 * 60 * 60 - minutes * 1000 * 60) / 1000);
        var ret = seconds + '秒';
        if (minutes > 0) {
            ret = minutes + '分' + ret;
        }
        if (hours > 0) {
            ret = hours + '小时' + ret;
        }
        return ret;
    };

    /**
     * 格式化时间
     */
    Tools.getFormattedTime = function (time, includeSeconds) {
        var dt = new Date(time);
        var hours = dt.getHours();
        if (hours < 10) {
            hours = '0' + hours;
        }
        var minutes = dt.getMinutes();
        if (minutes < 10) {
            minutes = '0' + minutes;
        }
        if (includeSeconds) {
            var seconds = dt.getSeconds();
            if (seconds < 10) {
                seconds = '0' + seconds;
            }
            return hours + ':' + minutes + ':' + seconds;
        }
        return hours + ':' + minutes;
    };

    /**
     * 格式化当前时间
     */
    Tools.getFormattedNowTime = function (includeSeconds) {
        return Tools.getFormattedTime(new Date().getTime(), includeSeconds);
    };


    /**
     * 自动对图片resize
     * @param maxWidth
     * @param maxHeight
     * @param objImg
     */
    Tools.autoResizeImage = function (maxWidth, maxHeight, objImg) {
        var img = new Image();
        img.src = objImg.src;
        var ratio = 1, w = objImg.width, h = objImg.height, wRatio = maxWidth / w, hRatio = maxHeight / h;
        if (maxWidth == 0 && maxHeight == 0) {
            ratio = 1;
        } else if (maxWidth == 0) {
            if (hRatio < 1) ratio = hRatio;
        } else if (maxHeight == 0) {
            if (wRatio < 1) ratio = wRatio;
        } else if (wRatio < 1 || hRatio < 1) {
            ratio = (wRatio <= hRatio ? wRatio : hRatio);
        }
        if (ratio < 1) {
            w = w * ratio;
            h = h * ratio;
        }
        objImg.height = h;
        objImg.width = w;
    };

    /**
     * 显示原图
     */
    Tools.showOriginImage = function(img, chatServerAddr) {
    	var src = $(img).attr('data-url')
	    if (!src) {
	    	src = img.src;
	    }
    	window.open(chatServerAddr + '/imgViewer.html?url=' + src, "_imgWin", "menubar=no,toolbar=no,titlebar=no,status=no");
    };

    Tools.removeItemFromArr = function (array, item) {
        var i;
        if ($.isArray(array) &&
            (i = array.indexOf(item)) > -1) {
            array.splice(i, 1);
        }
        return array;
    };
    
    /**
     * 获取当前鼠标选中的文本内容
     */
    Tools.getSelectionText = function() {
    	try {
            if (window.getSelection) {
                return window.getSelection().toString();
            } else if (document.selection && document.selection.createRange) {
                return document.selection.createRange().text;
            }
        } catch (e) {
        }
        return '';
    };
    
    /**
     * 根据队列id获取属性值，如果属性是字符串，则直接返回本身
     */
    Tools.getPropertyByQueue = function(property, queueId, defaultValue) {
		if (property) {
			if (typeof(property) === 'object') {
				return property[queueId] || defaultValue;
			} else {
				return property;
			}
		}
		return defaultValue;
	};
    
    Tools.setEndOfContenteditable = function(contentEditableElement) {
        var range,selection;
        if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
        {
            range = document.createRange();//Create a range (a range is a like the selection but invisible)
            range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
            range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
            selection = window.getSelection();//get the selection object (allows you to change selection)
            selection.removeAllRanges();//remove any selections already made
            selection.addRange(range);//make the range you have just created the visible selection
        }
        else if(document.selection)//IE 8 and lower
        { 
            range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
            range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
            range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
            range.select();//Select the range (make it the visible selection
        }
    };
    
    
    Tools.isFormattedMsg = function(formattedMsg) {
    	try {
    		var regexp = /^\[MessageFormat([^\]]*)\]([\s\S]*)\[\/MessageFormat\]$/;
    		var ret = regexp.exec(formattedMsg);
    		if (ret && ret.length === 3) {
    			return true;
    		}
    	} catch (e) {}
    }
    /**
     * 解析格式化的消息
     * 
     * [MessageFormat data-type="robot" data-key="BOT002"]{"commands":[{"argNames":[],"args":["胃炎","胃炎","https://uat.aia.com.cn/robot/attachments/20180807114344698"],"name":"imgmsg","state":1}],"content":"","relatedQuestions":["胃炎","核保各类疾病问卷"],"similarity":1,"type":1}[/MessageFormat]
     */
    Tools.parseFormattedMsg = function(formattedMsg) {
    	var resultMsg = formattedMsg;
    	try {
    		var regexp = /^\[MessageFormat([^\]]*)\]([\s\S]*)\[\/MessageFormat\]$/;
    		var ret = regexp.exec(formattedMsg);
    		if (ret && ret.length === 3) {
    			var props = ret[1], msgContent = ret[2], pos, propsMap = {};
    			props = props.trim().replace(/\s+/g, ' ').split(' ');
    			
    			props.forEach(function(p) {
    				if ((pos = p.indexOf('=')) > 0) {
    					var key = p.substring(0, pos);
    					var value = p.substring(pos + 1).trim();
    					value = value.replace(/"/g, '');
    					propsMap[key] = value;
    				} else {
    					propsMap[p] = true;
    				}
    			});
    			
    			var dataType = propsMap['data-type'];
    			if (dataType === 'robot') {
    				var robotId = propsMap['data-key'];
    				msgContent = Tools.parseHtmlEntity(msgContent);
    				resultMsg = Robot.parseRobotMessage(msgContent, robotId);
    			}
    		}
    	} catch (e) {}
    	return resultMsg;
    };
    
    Tools.formatHtmlEntity = function(msg) {
    	if (msg) {
    		msg = msg.replace(/</g, "&lt;").replace(/>/g, "&gt;");
    	}
    	return msg;
    };
    Tools.parseHtmlEntity = function(msg) {
    	if (msg) {
    		msg = msg.replace(/&lt;/g, "<").replace(/&gt;/g, ">");
    	}
    	return msg;
    };
    
    Tools.confirm = function(message, success, fail) {
    	if (!Helper.masker) {// 兼容过老的ngs版本
    		return $F.confirm(message, success, fail);
    	}
    	var dialog = $("<div class='sys_dialog' tabIndex=-1 />").appendTo('body');
		var close = function() {
			Helper.masker.hide(dialog)
			dialog.remove();
		}
	
		var title = $("<div class='title unselectable' />").text('EliteCRM').appendTo(dialog);
		$("<a href='javascript:;' class='close_icon'></a>").appendTo(dialog).on('click', close);
		var content = $("<div class='content'></div>").appendTo(dialog);
		content.html(message);
		$('<span class="icon confirm"><i class="fas fa-question-circle"></i></span>').appendTo(content);
		
		var btnbar = $("<div class='btnbar'></div>").appendTo(dialog);
		$('<button class="unselectable chrome js_ok">' + ((window.i18n && i18n.message.ok) || '确定') + '</button>').appendTo(btnbar).on('click', close);
	
		var btnbar = $(".btnbar", dialog).addClass('confirm');
		$(">button.js_ok", btnbar).off('click').on('click', function(e) {
			Helper.masker.hide(dialog)
			if ($.isFunction(success))
				success(dialog);
			dialog.remove();
		});
		$('<button class="chrome js_cancel">' + i18n.message.cancel + '</button>').appendTo(btnbar).click(function(e) {
			Helper.masker.hide(dialog)
			if ($.isFunction(fail))
				fail(dialog);
			dialog.remove();
		});
		
		dialog.on('keydown', function(e) {
			if (e.keyCode == 27) {
				Helper.masker.hide(dialog);
			}
		}).on('click', function(e) {
			e.stopPropagation();
		})

		Helper.masker.show(dialog, {
			onOpen : function() {
				$('.js_ok', dialog).focus();
			},
			onClose: function() {
				dialog.off('click');
			}
		});
    }

    var Robot = {
    	init: function(project) {
    		Robot.project = project;
    	},
    
    	ROBOT_ID: {
            "KM": "BOT000",
            "YIBOT": "BOT001",
            "XIAOI": "BOT002",
            "XIAODUO": "BOT003",
            "SOBOT": "BOT004"
        },

        /**
         * 替换[link url=""][/link] => <a href=\"\"></a>
         * @param str
         * @returns {*}
         */
        wrapLink: function (answer) {
            if (answer) {
                var reg1 = new RegExp(/\[link(.*?)url="(.*?)"](.*?)\[\/link]/g);
                while (reg1.test(answer)) {
                    answer = answer.replace(reg1, '<a href=\'$2\' target="_blank">$3</a>');
                }
                var reg2 = new RegExp(/\[link(.*?)submit="(.*?)"](.*?)\[\/link]/g);
                while (reg2.test(answer)) {
                    answer = answer.replace(reg2, '<a onclick=\'sendComment("$3")\' href="javascript:void(0);">$3</a>');
                }
                var reg3 = new RegExp(/\[link](.*?)\[\/link]/g);
                while (typeof $config == 'object' && reg3.test(answer)) {
                    answer = answer.replace(reg3, '<a onclick=\'sendComment("$1")\' href="javascript:void(0);">$1</a>');
                }
                var reg4 = new RegExp(/\[link(.*?)post="(.*?)"](.*?)\[\/link]/g);
                while (reg4.test(answer)) {
                    answer = answer.replace(reg4, '<a onclick=\'sendComment("$2")\' href="javascript:void(0);">$3</a>');
                }
                var reg5 = new RegExp(/\[link(.*?)submit="(.*?)"]/g);
                while (reg5.test(answer)) {
                    answer = answer.replace(reg5, '<a onclick=\'sendComment("$2")\' href="javascript:void(0);">$2</a>');
                }
            }
            return answer
        },
        
        /**
         * 替换<a target="_blank" href=""></a> => <a target=\"_blank\" href=\"\"></a>
         * @param str
         * @returns {*}
         */
        wrapATag: function (str) {
            var reg = new RegExp(/<a target="_blank" href="([^\]]*)\">([^\]]*)<\/a>/i);
            while (reg.test(str)) {
                str = str.replace(reg, '<a target=\\\"_blank\\\" href=\\\"$1\\\">$2</a>');
            }
            return str;
        },

        /**
         * 去掉字符串中带有'CDATA'
         * @param str
         * @returns {*}
         */
        wrapCDATA: function (str) {
        	if (!str) 
        		return '';
            var reg = new RegExp(/<\!\[CDATA\[([\S\s].*)\]\]>/i);
            while (reg.test(str)) {
                str = str.replace(reg, '$1').replace('<![CDATA[]]>', '');
            }
            return str;
        },

        /**
         * 多条消息显示的列标题是 html
         * @param title 显示的提示名称
         * @param question 问题内容
         * @param answer 答案
         * @param i 第几条消息
         * @returns {string}
         */
        domAnswerTitleAppend: function (title, question, answer, i) {
        	var href = 'javascript:;';
        	if (message.ra)
        		href = '' + message.ra.path;
            return '<div class="each-message">' +
                '<div class="message-title" data-title = "' + title + '" data-question = \'' + (title || question) + '\' >' +
                '<a href="' + href + '" target="_blank">' + (i + 1) + '. ' + (title || question) + '</a>' +
                '</div>' +
                '<div class="message-preview" style="display: none">' + answer + '</div>' +
                '</div>';
        },

        /**
         * 图文模板需要拼接的 html
         */
        domImageText: {
            domImageTextHomeAppend: function () {
                return '<ul class="tb-view">';
            },

            domImageTextEndAppend: function () {
                return '</ul>';
            },

            /**
             * 图文消息主体
             * @param title 标题
             * @param description 描述
             * @param picUrl 图片地址
             * @param url 文章链接
             * @param isFirst 是否是第一条图文内容
             * @returns {string}
             */
            domImageText: function (title, description, picUrl, url, isFirst) {
                var html = "";
                if (isFirst) {
                    html += '<li class="tb-cell tb-cell_first">' +
                        '<a href="' + url + '" target="_blank">' +
                        '<div class="first-img">' +
                        '<img src="' + picUrl + '" alt="' + title + '" class="tb-img fl" />' +
                        '</div>';
                } else {
                    html += '<li class="tb-cell">' +
                        '<a href="' + url + '" target="_blank">' +
                        '<img src="' + picUrl + '" alt="' + title + '" class="tb-img fl" />';
                }
                html += '<div class="tb-body">' +
                    '<span>' + title + '</span>' +
                    '<p class="tb-content">' + description + '</p>' +
                    '</div>' +
                    '</a>' +
                    '</li>';
                return html;

            }
        },
        

        /**
         * 解析机器人结果成html
         */
        messageHtml: {
            "KM": function (text) {
            	var KMURL = Robot.project.getParam('KMURL');
            	if (KMURL) {
            		KMURL = KMURL.substring(0, KMURL.lastIndexOf('/'));
            	}
                var html = '';
                try {
                	text.replaceAll('\r\n', '').replaceAll('\n\r', '').replaceAll('\r', '').replaceAll('\n', '').replaceAll('\b', '');
                    text = JSON.parse(text);
                    var question = text.question;
                    var srs = text.srs;
                    if (srs && srs.length > 0) {
                    	$.each(srs, function (i, item) {
                    		var href = 'javascript:;';
                        	if (item.ra)
                        		href = KMURL + item.ra.path;
                        	html += '<div class="each-message">' +
                                '<div class="message-title" data-title = "' + item.title + '" data-question = \'' + (item.title || item.question) + '\' >' +
                                '<a href="' + href + '" target="_blank">' + (i + 1) + '. ' + (item.title || item.question) + '</a>' +
                                '</div>' +
                                '<div class="message-preview" style="display: none">' + item.preview + '</div>' +
                                '</div>';
                        })
                    } else {
                    	html += '<div class="each-message">' +
                        '<div class="message-preview">' + text.message + '</div>' +
                        '</div>';
                    }
                    
                } catch (e) {
                	$F.log('chat-common', '异常数据', text);
                }
                return html;
            },

            "YIOBT": function (text) {
                var html = '';
                try {
                	if (typeof text != 'object') {
                        text = text.replaceAll('\r\n', '<br>').replaceAll('\n\r', '<br>').replaceAll('\r', '<br>').replaceAll('\n', '<br>').replaceAll('\b', ' ');
                        text = JSON.parse(text);
                    }
                    text = text.replaceAll('\r\n', '<br>').replaceAll('\n\r', '<br>').replaceAll('\r', '<br>').replaceAll('\n', '<br>').replaceAll('\b', ' ');
                    text = JSON.parse(text);
                    if (text.status == 0) {
                        if (text.type == 200) {
                            var result = text.info[0];
                            if (result.answer == 'zrg') {//转人工
                                return '转人工操作';
                            }
                            if ('image-text' == result.answerType) {
                                var answerjson = result.answerjson;
                                if (answerjson.length > 0) {
                                    html += Robot.domImageText.domImageTextHomeAppend();
                                    $.each(answerjson, function (i, item) {
                                        var isFirst = false;
                                        if (i == 0) isFirst = true;
                                        html += Robot.domImageText.domImageText(item.title, item.desc, item.pic_url, item.url, isFirst)
                                    })
                                    html += Robot.domImageText.domImageTextEndAppend();
                                }
                            }
                            else if ("single-image" == result.answerType) {
                                var imageUrl = result.pic_url;
                                html = '<img src="' + imageUrl + '"/>'

                            } else {
                                html = result.answer;
                            }
                        }
                        else if (text.type == 300) {
                            var resultArr = text.info;
                            $.each(resultArr, function (i, item) {
                                html += Robot.domAnswerTitleAppend(item.question, item.question, item.answer, i);
                            })
                        }
                        var relate = text.relate;
                        if (relate && relate.length > 0) {
                            html += '<div class="relate_title">你可能还想问这些问题,点击问题获取答案：</div>';
                            html += '<div class="relate_body"><ul>';
                            $.each(relate, function (j, item) {
                                html += '<li class="relate_body_li">' + item + '</li>'
                            })
                            html += '</ul></div>';
                        }
                    }
                } catch (e) {
                	$F.log('chat-common', '异常数据', text);
                }
                return html;
            },

            "XIAOI": function (text) {
                var html = '';
                try {
                	if (typeof text != 'object') {
                        text = text.replaceAll('\r\n', '<br>').replaceAll('\n\r', '<br>').replaceAll('\r', '<br>').replaceAll('\n', '<br>').replaceAll('\b', ' ');
                        text = Robot.wrapLink(text);
//                        text = Robot.wrapATag(text);
                        $F.log('chat-common', 'parseRobotMessage', text);
                        text = JSON.parse(text);
                    }
                    var content = text.content.replaceAll('“', '').replaceAll('”', '');
                    switch (text.type) {
                        case 1: //标准回复
                            var commands = text.commands;
                            $.each(commands, function (c, args) {
                                if (args.state == 1) {
                                    var name = args.name;
                                    if ('imgmsg' == name.toLowerCase()) {
                                        var arg = args.args;
                                        html += '<image src="' + arg[2] + '" alt="' + arg[0] + '" style="max-width:300px;max-height:300px"/>';
                                    }
                                    else if ('imgtxtmsg' == name.toLowerCase()) {  //图文信息
                                        var arg = args.args[3];
                                        if (arg) {
                                            arg = arg.substring(9, arg.length - 3);
                                            var xmlDoc = $.parseXML(arg), $xml = $(xmlDoc), $item = $xml.find("item");
                                            html += Robot.domImageText.domImageTextHomeAppend();
                                            $.each($item, function (i, item) {
                                                var isFirst = false;
                                                if (i == 0) isFirst = true
                                                html += Robot.domImageText.domImageText(Robot.wrapCDATA($(this).find('Title').html()),
                                                    Robot.wrapCDATA($(this).find('Description').html()),
                                                    Robot.wrapCDATA($(this).find('PicUrl').html()),
                                                    Robot.wrapCDATA($(this).find('Url').html()), isFirst)
                                            })
                                            html += Robot.domImageText.domImageTextEndAppend();
                                        }
                                    }
                                    else if ('P4' == name.toUpperCase()) {
                                        var arg = args.args;
                                        html += '<a target="_blank" href="' + arg[0] + '">' + arg[1] + '</a>';
                                    }
                                }
                            })

                            html += content;
                            break;
                        case 101: //转人工客服
                            if (content) {
                                if (content == 'SFYZ' || content == 'SJSFYZ' || content == 'SJYZ') {  //进行身份校验
                                    html = "身份校验操作";
                                } else if (content.indexOf("ZRG") > -1) {
                                        html = "转人工操作";
                                } else {
                                        html = content;
                                }
                            }
                            break;
                        default:
                            html += text.content;
                    }
                    html = Robot.wrapLink(html);
                	var BOTRQS = Robot.project.getParam('BOTRQS');
                	if (BOTRQS) {
                        var relatedQuestions = text.relatedQuestions;
                        if (relatedQuestions && relatedQuestions.length > 0) {
                            html += '<div class="relate_title">你可能还想问这些问题,点击问题获取答案：</div>';
                            html += '<div class="relate_body"><ul>';
                            $.each(relatedQuestions, function (j, item) {
                                html += '<li class="relate_body_li">' + item + '</li>'
                            })
                            html += '</ul></div>';
                        }
                    }
            	} catch (e) {
            		$F.log('chat-common', '异常数据', text);
				}
                return html;
            },
            "XIAODUO": function (text) {
            	var html = '';
            	try{
	            	if (typeof text != 'object') {
	            		$F.log('chat-common', 'parseRobotMessage', text);
	            		text = JSON.parse(text);
	            	}
	                if (text.error_code == 0) {
	                    var data = text.data;
	                    var state = data.state;
	                    if (state == 1) {
	                        var answers = data.answers;
	                        if (answers.length > 0) {
	                            $.each(answers, function (i, answer) {
	                                html += answer;
	                            })
	                        }
	                        var relatedQuestions = data.related_questions;
	                        if (relatedQuestions.length > 0) {
	                            html += '推荐给您的相关问题：<br>';
	                            $.each(relatedQuestions, function (i, relatedQuestion) {
	                                html += '<li class="relate_body_li">' + relatedQuestion + '</li>';
	                            })
	                        } else {
	                            var hotQuestions = data.hot_questions;
	                            if (hotQuestions.length > 0) {
	                                html += '推荐给您的热点知识：<br>';
	                                $.each(hotQuestions, function (i, hotQuestion) {
	                                    html += '<li class="relate_body_li">' + hotQuestion + '</li>';
	                                })
	                            } else {
	                            	html += "未找到相关的问题答案";
	                            }
	                        }
	                    }
	                    else if (state == 2) {
	                        var recommends = data.recommend;
	                        if (recommends.length > 0) {
	                            $.each(recommends, function (i, recommend) {
	                                html += '<li class="relate_body_li">' + recommend + '</li>';
	                            })
	                        } else {
	                        	html += "未找到相关的问题答案";
	                        }
	                    }
	                    else if (state == 3) {
	                        var recommends = data.recommend;
	                        if (recommends.length > 0) {
	                            $.each(recommends, function (i, recommend) {
	                                html += '<li class="relate_body_li">' + recommend + '</li>';
	                            })
	                        } else {
	                        	if (data.trans_to_human) {
	                        		html += '亲，由于这个问题暂时无法解答，给你带来不便非常抱歉，是否为您转人工服务呢！';
	                        	} else {
	                        		html += '亲，能否重新阐述一下，这能让我更好的为您解答问题！ ';
	                        	}
	                        }
	                    } else {
	                    	html += "未找到相关的问题答案";
	                    }
	                } else {
	                    $F.log("接口异常" + text.error_code);
	                }
            	} catch (e) {
        			$F.log('chat-common', '异常数据', text);
        		}
            	return html;
            },
            "SOBOT": function (text) {
                var html = '';
                try {
	                if (typeof text !== 'object') {
                        text = JSON.parse(text);
	            	}
	                if (text && text.code == '1000') {
	                    var data = text.data;
	                    if (data && data.answer) {
	                        html = data.answer;
	                    } else {
	                        html = "没有对应的机器人答案，请换一种问法试试。";
	                    }
	                } else {
	                    html = "机器人异常";
	                }
                } catch (e) {
                	html = "机器人异常";
                	$F.log('chat-common', '异常数据', text);
        		}
                return html;
            }
        },
        /**
         * 判断这个坐席是不是机器人坐席
         */
        isRobot: function (userId) {
            return userId == Robot.ROBOT_ID.KM || userId == Robot.ROBOT_ID.YIBOT || userId == Robot.ROBOT_ID.XIAOI || userId == Robot.ROBOT_ID.XIAODUO || userId == Robot.ROBOT_ID.SOBOT;
        },
        
        /**
         * 解析机器人消息
         */
        parseRobotMessage: function (message, userId) {
        	var msgText = message ? message : '';
        	if (!msgText || msgText === 'null') return '';
			if (userId == Robot.ROBOT_ID.KM) {
                msgText = Robot.messageHtml.KM(msgText);
            } else if (userId == Robot.ROBOT_ID.YIBOT) {
                msgText = Robot.messageHtml.YIOBT(msgText);
            } else if (userId == Robot.ROBOT_ID.XIAOI) {
                msgText = Robot.messageHtml.XIAOI(msgText);
            } else if (userId == Robot.ROBOT_ID.XIAODUO) {
                msgText = Robot.messageHtml.XIAODUO(msgText);
            } else if (userId == Robot.ROBOT_ID.SOBOT) {
                msgText = Robot.messageHtml.SOBOT(msgText);
            }
			return msgText;
        },
        
        /**
         * 为坐席辅助聊天解析机器人返回消息
         * @param question 客户提问的问题
         * @param responseText 机器人返回数据
         * @param userId 机器人id
         */
        parseRobotMessageForAgentAssist: function(question, responseText, userId) {
        	if (!responseText) return null;
            if (userId == Robot.ROBOT_ID.KM) {
                
            } else if (userId == Robot.ROBOT_ID.YIBOT) {
                
            } else if (userId == Robot.ROBOT_ID.XIAOI) {
                
            } else if (userId == Robot.ROBOT_ID.XIAODUO) {
            	if (typeof responseText !== 'object') {
            		$F.log('chat-common', 'parseRobotMessageForAgentAssist: ' + responseText);
            		try {
             			responseText = JSON.parse(responseText);
            		} catch (e) {
            			$F.log('chat-common', '异常数据', responseText)
            			return;
            		}
            	}
                if (responseText.error_code === 0) {
                    var data = responseText.data;
                    var state = data.state;
                    if (state == 1) {
                    	//{"error_code":0,"info":"","lp":"ec_0","data":{"msg_id":47078024,"user_id":"095875bc-6ba4-4199-ed8e-9b23aea8815f","question":"无法识别","answers":[],"options":[],"recommend":[],"related_questions":[],"hot_questions":[],"trans_to_human":false,"inspects":[],"state":3}}
                    	var msgContainer = $('<div class="robotResponseWrapper"><p class="question">' + question + '<i class="arrowDown far fa-angle-down" style="display:none"/><i class="arrowUp far fa-angle-up"/></p></div>');
                    	var answers = data.answers;
                        if (answers.length > 0) {
                        	$('<p class="content">' + answers[0] + '</p>').appendTo(msgContainer);
                        }
                    	return $('<div>').append(msgContainer).html();
                    }
                }
            }
        },
        
        /**
         * 坐席机器人辅助信息事件包装
         */
        wrapResponse: function(response, callback) {
        	var msgContainer = $(response);
        	$('.arrowDown', msgContainer).on('click', function(){
				var arrowDown = $(this), container = $(this).parent().parent();
        		$('.content', container).slideDown(500);
        		arrowDown.hide();
        		$('.arrowUp', container).show();
        	});
        	$('.arrowUp', msgContainer).on('click', function(){
        		var arrowUp = $(this), container = $(this).parent().parent();
        		$('.content', container).slideUp(500);
        		$('.arrowDown', container).show();
        		arrowUp.hide();
        	});
        	$('.content', msgContainer).on('click', function(){
        		callback && callback($(this).text());
        	});
        	return msgContainer;
        }
    }

    return {
        EMOTION: EMOTION,
        ICONS: ICONS,
        REQUEST_STATUS: REQUEST_STATUS,
        CHAT_REQUEST_TYPE: CHAT_REQUEST_TYPE,
        USER_STATUS: USER_STATUS,
        CLIENT_TYPE: CLIENT_TYPE,
        NOTICE_TYPE: NOTICE_TYPE,
        SoundManager: SoundManager,
        Tools: Tools,
        Robot: Robot
    }
});